#ifndef __PROVIDER_API_H__
#define __PROVIDER_API_H__

#include <map>
#include <string>

#include "crossplatform.h"

class FilesystemProvider;
class ProviderFile;
class ProviderDir;
class Configuration;
class UserInterface;


typedef unsigned long long uint64_t;

#define STAT_FLAG_TYPE_MASK    0xF0000000
#define STAT_FLAG_IS_DIRECTORY 0x80000000
#define STAT_FLAG_IS_SOCKET    0x90000000
#define STAT_FLAG_IS_FIFO      0xA0000000
#define STAT_FLAG_IS_CHARDEV   0xB0000000
#define STAT_FLAG_IS_BLOCKDEV  0xC0000000
#define STAT_FLAG_IS_FILE      0xD0000000

#define STAT_FLAG_READ_ONLY    0x08000000
#define STAT_FLAG_IS_SYMLINK   0x04000000
#define STAT_FLAG_HIDDEN       0x02000000

#define STAT_VALID_SIZE        0x00000001
#define STAT_VALID_TIMES       0x00000002
#define STAT_VALID_UNIXPERMS   0x00000004
#define STAT_VALID_UNIXOWNGRP  0x00000008
#define STAT_VALID_TYPE        0x00000010

struct DirStatInfo
{
	unsigned long ValidityFlags;
	uint64_t FileSize;
	uint64_t CreationTime, WriteTime;
	unsigned long Attributes;
	unsigned long UnixOwner, UnixGroup;
	unsigned long UnixPermMask;

	unsigned char *Acl;
	size_t AclSize;

	char *Name;
	size_t NameLen;
};

typedef FilesystemProvider* (*FsCreateFunc)(UserInterface *ui, const Configuration& cfg);
typedef void (*FsListFunc)(const char *name, size_t namelen, const DirStatInfo& info, void *context);

enum OpenType
{
	OpenUndefined,
	OpenCreateNew,
	OpenCreateAlways,
	OpenOpenExisting,
	OpenOpenAlways,
	OpenTruncateExisting,
};

class FilesystemProvider
{
public:
	virtual ~FilesystemProvider() {}

	virtual int Start() = 0;
	virtual void Stop() = 0;

	virtual int OpenFile(ProviderFile **f, ProviderDir **d, const std::string& path, OpenType type, bool create_ro, bool open_writable) = 0;
	virtual int Rename(const std::string& from, const std::string& to, bool overwrite_existing) = 0;

	virtual void GetDiskInfo(uint64_t& free_total, uint64_t& free_quota, uint64_t& total_quota) = 0;

	virtual std::string GetFsType() = 0;

	static void RegisterFs(const char *name, FsCreateFunc func);
	static FsCreateFunc LookupFs(const std::string& name);

private:
	static std::map<std::string, FsCreateFunc> *KnownFsList;
};

class ProviderCommon
{
public:
	ProviderCommon() { RefCount = 1; }
	virtual ~ProviderCommon() {}

	virtual const DirStatInfo& Stat() = 0;

	virtual int Delete() = 0;

	virtual ProviderDir* Dir() { return NULL; }
	virtual ProviderFile* File() { return NULL; }

	void Reference()
	{
		InterlockedIncrement(&RefCount);
	}

	void Dereference()
	{
		if(InterlockedDecrement(&RefCount) == 0)
			delete this;
	}

	bool LastReference()
	{
		return RefCount == 1;
	}

private:
	long RefCount;
};

class ProviderDir : public ProviderCommon
{
public:
	virtual ~ProviderDir() {}
	virtual ProviderDir* Dir() { return this; }

	virtual int ListFiles(FsListFunc cb, void *context) = 0;
};

class ProviderFile : public ProviderCommon
{
public:
	virtual ~ProviderFile() {}
	virtual ProviderFile* File() { return this; }

	virtual int Read(void *buffer, unsigned long long offset, unsigned long size, unsigned long& transferred) = 0;
	virtual int Write(void *buffer, unsigned long long offset, unsigned long size, unsigned long& transferred) = 0;
	virtual int Flush() = 0;
	virtual int Resize(unsigned long long size) = 0;

};

#define DEFINE_FS(name, func) class __singleton_init { public: __singleton_init() { FilesystemProvider::RegisterFs(#name, func); } } __init


#endif
